#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include "Err.hpp"
#include <errno.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string>

using namespace std;

class Sock // 只关心读事件
{
    static const int defaultbacklog = 10; // TCP链接等待队列的默认大小
public:
    // 构造
    Sock(const int port)
        : _listensock(-1), _port(port)
    {
    }

    // 析构
    ~Sock()
    {
        if (_listensock >= 0)
            close(_listensock);
    }

    // 创建套接字
    void Create()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
            exit(SOCK_CREATE_FAILED);
    }

    // 绑定套接字
    void Bind()
    {
        // 1、初始化属性信息
        struct sockaddr_in infor;
        bzero(&infor, sizeof(infor));
        infor.sin_addr.s_addr = htonl(INADDR_ANY); // ip地址
        infor.sin_port = htons(_port);             // 端口号
        infor.sin_family = AF_INET;                // 通信方式
        // 2、绑定(成功返回0，失败返回-1)
        if (bind(_listensock, (struct sockaddr *)&infor, sizeof(infor)) < 0)
            exit(SOCK_BIND_FAILED);
    }

    // 监听套接字
    void Listen()
    {
        if (listen(_listensock, defaultbacklog) < 0) // 成功返回0，失败返回-1
            exit(SOCK_LISTEN_FAILED);
    }

    //获取一个新链接
    int Accept(string &clientip, string &clientport)
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        bzero(&client, sizeof(client));

        int sock = accept(_listensock, (struct sockaddr *)&client, &len);
        if (sock < 0) // 获取失败，直接返回sock
            return sock;
        else // 获取成功，返回clientip和clientport
        {
            clientip = inet_ntoa(client.sin_addr);//将网络整型IP地址转化成本地字符串形式
            clientport = ntohs(client.sin_port);//将大端字节序端口号转化成本地模式
            return sock;
        }
    }

    //获取文件描述符
    int getsock()
    {
        return _listensock;
    }

private:
    int _listensock; // 监听描述符
    int _port;       // 端口号
};